package com.quxiu.system.service.impl;

import java.util.Date;
import java.util.List;

import com.alibaba.fastjson2.JSONObject;
import com.quxiu.common.core.exception.ServiceException;
import com.quxiu.common.core.utils.DateUtils;
import com.quxiu.common.core.utils.StringUtils;
import com.quxiu.common.core.utils.security.KeyPairVo;
import com.quxiu.common.core.utils.security.SecretUtil;
import com.quxiu.common.core.utils.uuid.UUID;
import com.quxiu.system.api.domain.SysDept;
import com.quxiu.system.api.domain.SysUser;
import com.quxiu.system.constant.AppConstant;
import com.quxiu.system.constant.DataPushConstant;
import com.quxiu.system.constant.PushDataType;
import com.quxiu.system.constant.PushEvent;
import com.quxiu.system.domain.SysDataPushRecord;
import com.quxiu.system.domain.vo.PushDataResult;
import com.quxiu.system.domain.vo.PushDataVo;
import com.quxiu.system.mapper.SysDataPushRecordMapper;
import com.quxiu.system.mapper.SysDeptMapper;
import com.quxiu.system.mapper.SysUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import com.quxiu.system.mapper.SysAppMapper;
import com.quxiu.system.domain.SysApp;
import com.quxiu.system.service.ISysAppService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

/**
 * 应用Service业务层处理
 *
 * @author GaoYang
 * @date 2024-01-19
 */
@Slf4j
@Service
public class SysAppServiceImpl implements ISysAppService {
    @Resource
    private SysAppMapper sysAppMapper;
    @Resource
    private SysDataPushRecordMapper sysDataPushRecordMapper;
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private SysDeptMapper sysDeptMapper;
    @Resource
    private RestTemplate restTemplate;

    /**
     * 查询应用
     *
     * @param appId 应用主键
     * @return 应用
     */
    @Override
    public SysApp selectSysAppByAppId(String appId) {
        return sysAppMapper.selectSysAppByAppId(appId);
    }

    /**
     * 查询应用列表
     *
     * @param sysApp 应用
     * @return 应用
     */
    @Override
    public List<SysApp> selectSysAppList(SysApp sysApp) {
        return sysAppMapper.selectSysAppList(sysApp);
    }

    /**
     * 新增应用
     *
     * @param sysApp 应用
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertSysApp(SysApp sysApp) {
        sysApp.setAppId(UUID.randomUUID(true).toString().replace("-", ""));
        sysApp.setCreateTime(DateUtils.getNowDate());
        KeyPairVo key = SecretUtil.generateRsaKeyHex();
        sysApp.setPublicKey(key.getPublicKey());
        sysApp.setPrivateKey(key.getPrivateKey());
        return sysAppMapper.insertSysApp(sysApp);
    }

    /**
     * 修改应用
     *
     * @param sysApp 应用
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateSysApp(SysApp sysApp) {
        sysApp.setUpdateTime(DateUtils.getNowDate());
        return sysAppMapper.updateSysApp(sysApp);
    }

    /**
     * 批量删除应用
     *
     * @param appIds 需要删除的应用主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteSysAppByAppIds(String[] appIds) {
        sysDataPushRecordMapper.deleteByAppIds(appIds);
        return sysAppMapper.deleteSysAppByAppIds(appIds);
    }

    /**
     * 删除应用信息
     *
     * @param appId 应用主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteSysAppByAppId(String appId) {
        sysDataPushRecordMapper.deleteByAppId(appId);
        return sysAppMapper.deleteSysAppByAppId(appId);
    }

    @Override
    public void pushUserDataAll(String appId) {
        SysApp app = sysAppMapper.selectSysAppByAppId(appId);
        if (app == null) {
            throw new ServiceException("无效的appId");
        }
        if (!PushDataType.contains(app.getPushDataType(), PushDataType.USER)) {
            throw new ServiceException("该应用未开启推送用户数据功能");
        }

        // 删除未推送的记录
        sysDataPushRecordMapper.deleteByAppIdAndPushDataType(appId, PushDataType.USER.getCode());

        List<SysUser> userList = sysUserMapper.selectUserList(new SysUser());
        if (CollectionUtils.isNotEmpty(userList)) {
            userList.parallelStream().forEach(user -> {
                this.addSysDataPushRecord(appId, PushDataType.USER.getCode(), PushEvent.ADD.getCode()
                        , String.valueOf(user.getUserId()), this.formatPushData(PushDataType.USER, user));
            });
        }
    }

    @Override
    public void pushDeptDataAll(String appId) {
        SysApp app = sysAppMapper.selectSysAppByAppId(appId);
        if (app == null) {
            throw new ServiceException("无效的appId");
        }
        if (!PushDataType.contains(app.getPushDataType(), PushDataType.DEPT)) {
            throw new ServiceException("该应用未开启推送部门数据功能");
        }

        // 删除未推送的记录
        sysDataPushRecordMapper.deleteByAppIdAndPushDataType(appId, PushDataType.DEPT.getCode());

        List<SysDept> deptList = sysDeptMapper.selectDeptList(new SysDept());
        if (CollectionUtils.isNotEmpty(deptList)) {
            deptList.parallelStream().forEach(dept -> {
                this.addSysDataPushRecord(appId, PushDataType.DEPT.getCode(), PushEvent.ADD.getCode()
                        , String.valueOf(dept.getDeptId()), this.formatPushData(PushDataType.DEPT, dept));
            });
        }
    }

    @Override
    public void pushDataIncr(PushDataType dataType, PushEvent pushEvent, String bizId, Object pushData) {
        if (pushData == null) {
            return;
        }
        if (PushDataType.USER.equals(dataType)) {
            if (!(pushData instanceof SysUser)) {
                throw new ServiceException("推送数据类型错误");
            }
        } else if (PushDataType.DEPT.equals(dataType)) {
            if (!(pushData instanceof SysDept)) {
                throw new ServiceException("推送数据类型错误");
            }
        } else {
            throw new ServiceException("推送数据类型错误");
        }

        SysApp appParam = new SysApp();
        appParam.setStatus(AppConstant.STATUS_ENABLE);
        List<SysApp> appList = sysAppMapper.selectSysAppList(appParam);
        if (CollectionUtils.isNotEmpty(appList)) {
            appList.parallelStream().forEach(app -> {
                if (PushDataType.contains(app.getPushDataType(), dataType)) {
                    this.addSysDataPushRecord(app.getAppId(), dataType.getCode(), pushEvent.getCode()
                            , bizId, this.formatPushData(dataType, pushData));
                }

            });
        }

    }

    private void addSysDataPushRecord(String appId, String pushDataType, String pushEvent, String bizId, String pushData) {
        SysDataPushRecord record = new SysDataPushRecord();
        record.setAppId(appId);
        record.setPushDataType(pushDataType);
        record.setPushEvent(pushEvent);
        record.setBizId(bizId);
        record.setPushData(pushData);
        record.setPushStatus(DataPushConstant.PUSH_STATUS_WAIT);
        record.setCreateTime(new Date());
        sysDataPushRecordMapper.insertSysDataPushRecord(record);
    }

    /**
     * 格式化推送数据
     * @param dataType
     * @param pushData
     * @return
     */
    private String formatPushData(PushDataType dataType, Object pushData) {
        if (PushDataType.USER.equals(dataType)) {
            return this.formatPushUserData(pushData);
        } else if (PushDataType.DEPT.equals(dataType)) {
            return this.formatPushDeptData(pushData);
        }
        return null;
    }

    private String formatPushUserData(Object pushData) {
        SysUser user = (SysUser) pushData;
        JSONObject data = new JSONObject();
        data.put("userId", user.getUserId());
        data.put("deptId", user.getDeptId());
        data.put("userName", user.getUserName());
        data.put("nickName", user.getNickName());
        data.put("email", user.getEmail());
        data.put("phonenumber", user.getPhonenumber());
        data.put("sex", user.getSex());
        data.put("status", user.getStatus());

        return data.toJSONString();
    }

    private String formatPushDeptData(Object pushData) {
        SysDept dept = (SysDept) pushData;
        JSONObject data = new JSONObject();
        data.put("deptId", dept.getDeptId());
        data.put("deptName", dept.getDeptName());
        data.put("parentId", dept.getParentId());
        data.put("leader", dept.getLeader());
        data.put("status", dept.getStatus());

        return data.toJSONString();
    }

    @Override
    public void executePushData() {
        SysApp appParam = new SysApp();
        appParam.setStatus(AppConstant.STATUS_ENABLE);
        List<SysApp> appList = sysAppMapper.selectSysAppListInner(appParam);
        if (CollectionUtils.isEmpty(appList)) {
            return;
        }

        appList.parallelStream().forEach(app -> {

            // 获取待推送数据
            SysDataPushRecord pushParam = new SysDataPushRecord();
            pushParam.setAppId(app.getAppId());
            pushParam.setPushStatus(DataPushConstant.PUSH_STATUS_WAIT);
            List<SysDataPushRecord> recordList = sysDataPushRecordMapper.selectSysDataPushRecordList(pushParam);
            if (StringUtils.isNotBlank(app.getPushDataUrl()) && CollectionUtils.isNotEmpty(recordList)) {
                for (SysDataPushRecord record : recordList) {
                    try {
                        PushDataVo pushData = new PushDataVo();
                        pushData.setAppId(app.getAppId());
                        pushData.setPushDataType(record.getPushDataType());
                        pushData.setPushEvent(record.getPushEvent());
                        pushData.setPushData(JSONObject.parseObject(record.getPushData()));

                        // 数据加密
                        String data = SecretUtil.encryptRsaForPrivateKey(JSONObject.toJSONString(pushData), app.getPrivateKey());

                        // 推送数据
                        HttpHeaders headers = new HttpHeaders();
                        headers.setContentType(MediaType.APPLICATION_JSON);
                        headers.add("appId", app.getAppId());
                        HttpEntity<String> httpEntity = new HttpEntity<String>(data, headers);
                        ResponseEntity<String> response = restTemplate.exchange(app.getPushDataUrl(), HttpMethod.POST, httpEntity, String.class);
                        if (response.hasBody()) {
                            PushDataResult result = JSONObject.parseObject(response.getBody(), PushDataResult.class);
                            if (result.isSuccess()) {
                                sysDataPushRecordMapper.updatePushResult(record.getRecordId()
                                        , DataPushConstant.PUSH_STATUS_FINISH, DataPushConstant.PUSH_RESULT_SUCCESS, response.getBody());
                            } else {
                                sysDataPushRecordMapper.updatePushResult(record.getRecordId(), DataPushConstant.PUSH_STATUS_WAIT
                                        , DataPushConstant.PUSH_RESULT_FAIL, response.getBody());
                            }
                        }
                    } catch (Exception e) {
                        log.error("执行数据推送 error, recordId = {} : ", record.getRecordId(), e);
                        sysDataPushRecordMapper.updatePushResult(record.getRecordId(), DataPushConstant.PUSH_STATUS_WAIT
                                , DataPushConstant.PUSH_RESULT_FAIL, e.toString());
                    }
                }
            }
        });
    }
}
